Create client-side charts with Highcharts

I’ve stumbled across a Highcharts announcement on ajaxian.com a few days ago. Highcharts looked like something I’ve been (passively) looking for for years: a simple tool that could take values generated by the server and turn them into a fancy graph. It lived up to the promise: after struggling with it for a few hours, I’ve deployed my first chart-on-a-page to production (note to myself: still have to fix the caching issues).

The tool works great, but there are (as always) a few hidden gotchas:

  • The reference manual gives you all the information, the How to use page is somewhat cryptic.
  • The demo pages show you incomplete code; all the formatting parameters are missing.
  • Although it’s obvious in the hindsight, the documentation “forgets” to mention that you have to style all the elements of the graph, otherwise you’ll get a nice white-on-white nothingness. You can dig through the demo code to find the routines that do that (they’re hidden in a JavaScript file) or look at my code.
  • Another missing bit: if you want to apply the same format to multiple graphs, set the default options with the Highcharts.setOptions(chartFormat) call.
  • Last but not least: the series parameter is an array of objects (each object having at least the data property). If you read the documentation too literally and define series as an object (not array), you’ll get a nicely formatted empty canvas (assuming you’ve got the formatting parameters in place).

A nasty Firebug “surprise”

If you happen to believe that the client-side XSLT transformations are a good thing (I am firmly footed in that camp), Firefox 3.x brings nothing but disappointments. Now it's Firebug's turn: they’ve managed to mangle the console.log function. It worked a while ago, but then a brilliant mind decided to re-implement it with a hidden DIV between the HEAD and the BODY element:

<div id="_firebugConsole" style="display: none;" FirebugVersion="1.4.5"/>

This DIV is created automatically for regular (X)HTML pages, but not for XSLT-generated content, so the output of console.log gets sent to /dev/null (plus you get loads of weird error messages).

Publish stories on Facebook

In my first Facebook-related article published by InformIT, I’ve described the basics of Facebook Connect – a JavaScript API that can connect your web application with millions of Facebook users. The next step is pretty obvious: once you’ve attracted the Facebook users, it makes sense to publish their activity on your web to their Facebook news feed. The process is described in my next InformIT article “Publish Your Application Stories to Facebook”.

jQuery event delegation

A new article published on the Learning jQuery blog explains the intricacies of event delegation and the new .live() jQuery method. The event delegation (a great feature) allows you to declare a single event that works on numerous children of the same parent (instead of binding a copy of the event-handling function to every child).

The .live() method goes a step beyond that and declares an event for every element matching its selector. However, the implementation of the .live() method is resource-consuming: it binds an event handler to the document root, so it’s involved every time the specified event occurs anywhere in the document.

Use Facebook Connect to Bring Your Application to Millions of Users

Almost a year ago, I’ve joined Facebook which has at that time rolled out the initial sandbox of the Facebook Connect environment. I’ve developed a very simple application and waited for the FB Connect rollout. A few months later (around December 2008) they got so far and I’ve deployed my application on my production server … only to get user complains a while later telling me the application has stopped working.

It turned out Facebook has (somewhat silently) changed their API enough that it broke my code. However, I only had to fix a few functions to adapt them to a now better-documented API. I’ve also used a few extra bits-and-pieces Facebook engineers threw in after discovering what we really need. The second FB Connect experience was so good that I’ve decided to write a series of articles for InformIT describing how you can integrate your web site with Facebook. The first one, Use Facebook Connect to Bring Your Application to Millions of Users, has just been published on the InformIT web site.

Learning jQuery book from Packt

When I’ve decided to start using jQuery, I bought a number of books to help me get started (my time is way too valuable to be spent on Google wild chase), including the jQuery Reference Guide from Packt. In the meantime they’ve published Learning jQuery 1.3 covering the latest major release of jQuery.

I’m waiting for my review copy from Packt (then I’ll be able to tell you more about the book) and they were kind enough to provide a link to a sample chapter that I can share with you.

Introduction to RDFa

I’ve finally found time to read the RDFa articles published on A List Apart. I have to digest the information and try to figure out whether it’s relevant to my web sites, but I’m already intrigued enough to publish the links for future reference:

Ajax with jQuery

The third jQuery article I wrote for InformIT covers the jQuery Ajax support. It describes simple Ajax calls that insert HTML fragments into the current web page, processing of XML responses, and global AJAX events that display the loading indicator.

My second jQuery article: refactoring a web page

When I’ve decided to switch from X library to jQuery, I was faced with tons of (now outdated) pages in my web site that I had to migrate to jQuery. As it turns out, doing the migration job properly is a great idea: armed with the CSS experience (and believing in the need for using tags that make sense) I was able to make compact, more readable and better degradable (an awful word to use in this context) web pages.

I’ve described some of the lessons I’ve learned in this process in the Web Page Refactoring with jQuery article that was published by InformIT.

XSLT: Truncate text with ellipsis

A great set of XSLT templates that allows you to truncate XHTML markup (or any XML node) at specified text length. I was impressed ;)

Firefox 3.5 XHTML support stinks

Continuing my Firefox “quality” rants: I just found the willpower to completely redesign my AJAX framework, going from IFRAMEs to jQuery AJAX calls (replacing straightforward and quite elegant XSL transformations with pages of convoluted JavaScript code) to work around the bugs in FF3.0, only to find out that FF3.5 is even worse and introduced numerous additional “features”.

For example, FF3.5 requires an explicit </script> tag within an XHTML document with proper DOCTYPE. The following document was validated with W3C XHTML validator …

<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>Test</title>
  <script src="… source URL … " type="text/javascript" />
</head>
<body id="body">
</body>
</html>

… but it does not load the script in FF3.5.

Before anyone starts telling me that it’s not so hard to include the closing </script> tag in your source – try telling that to the database with native XML support where I’m storing snippets of the code. I had to convert the field from XML to TEXT (and lose all XML goodies I might eventually get) just to avoid the elimination of the explicit closing tag.

May I make a quick suggestion to the FF developers: maybe, just maybe, you might want to consider supporting existing web applications in parallel with adding new features that not too many people can use (because no other browser supports them yet).

JS-Kit crashes a Blogger blog in Internet Explorer

Several times I’ve stumbled across Blogger-hosted blog that simply refused to open in Internet Explorer with the “Operation aborted” pop-up window and subsequent error page. I never tried to investigate what was going on (I simply copied the URL into another browser), but when I’ve installed JS-Kit on my blog, I’ve started getting the same problems … obviously a cause for a major alarm.

The Infinities Loop site provided an answer in the comments: a SCRIPT performing specific manipulations should be a child of BODY, not another HTML element. When I’ve moved the JS-Kit script (<script src='http://js-kit.com/extra/blogger/comments.js' type='text/javascript'/>) from the Blogger widget to the end of the page, the new fanciful JS-Kit-based comments worked flawlessly.

Introduction to jQuery article published by InformIT

After becoming a convert (and a somewhat quiet evangelist) to jQuery, I wrote a series of introductory articles for the InformIT.com web site. The first one, Introduction to jQuery, covers the basic concepts, including selectors, chaining, and the page ready event. It also contains a comparison between a “traditional” JavaScript code and jQuery code.

Refactoring a menu: Remove unnecessary IDs

If you’re new to this series, read the “Refactoring a simple menu” and “Remove inline CSS” first.

The original HTML code for the dropdown menu (see below) was full of IDs that were used as a DOM navigation tool (I’ve used getElementById instead of traversing the DOM tree). When moving from a simple wrapper JavaScript library (I was using the X library) to jQuery, it makes sense to use its powerful traversal functions to replace the ID-based navigation.

<div class="rowMenu" id="IDAHYJQB">
  <p><a href="/climbing/myClimbs/myClimbs.asp">First page</a></p>
</div>
<div class="rowMenu" id="IDAKYJQB">
  <script>menuRegister('IDAKYJQB')</script>
  <p id="IDAKYJQB_main"><a href="javascript:menuClick('IDAKYJQB')">Add ...</a></p>
  <div id="IDAKYJQB_sub">
    <p><a onclick="menuSelect('IDAKYJQB')" 
        href="/climbing/myClimbs/myClimbs_add.asp">New entry </a></p>
    <p><a onclick="menuSelect('IDAKYJQB')" 
        href="/climbing/myClimbs/myClimbs_editWall.asp?a=add">Edit</a></p>
    … more …
  </div>
</div>

The HTML code is interspersed with inline calls to three JavaScript functions:

  • menuRegister registers the ID of a drop-down menu
  • menuClick opens a drop-down menu
  • menuSelect hides the drop-down menu and

Today we’ll replace these functions with simpler jQuery equivalents while getting rid of element IDs.

The menuRegister function will not be needed once we fix the DOM traversal problem. The menuClick and menuSelect functions will be merged into a single menuClickEvent function that will identify whether it works on a main menu entry or an entry of a drop-down menu. The this variable will be passed to the menuClickEvent function to avoid any ID-based references.

The menuClickEvent function has to perform a few setup tasks:

  • Get the DOM element that was clicked, using either the function parameter or (for future use) the value of the this variable.
  • Get the parent paragraph.
  • Decide whether it’s operating on a top-row entry (the parent paragraph has a DIV sibling) or not.

Using jQuery makes the job extremely simple:

function menuClickEvent(thisParam) {
  var a = thisParam || this; 
  var p = $(a).parents('P:first');
  var d = p.siblings('DIV');
  var toprow = d.length != 0;

  … rest of the code …
}

If the menuClickEvent function works on an element of a drop-down menu, it should hide the drop-down menu and return true (indicating that the event handler should perform its default task), otherwise it should toggle the state of the down class of the current paragraph and the visibility of the sibling DIV. The jQuery-based code is much shorter, more elegant and way more readable than the original.

function menuClickEvent(thisParam) {
  var a = thisParam || this; 
  var p = $(a).parents('P:first');
  var d = p.siblings('DIV');
  var toprow = d.length != 0;

  if (toprow) {
    p.toggleClass('down');
    d.toggle();
    return false;
  } else {
    p.parents('DIV').hide().siblings('P').removeClass('down');
    return true;
  }
}

With the new jQuery-based implementation of the drop-down menu, we can get rid of all element IDs, resulting in much shorter HTML code:

<div class="rowMenu">
  <p><a href="/climbing/myClimbs/myClimbs.asp">First page</a></p>
</div>
<div class="rowMenu">
  <p><a href="#" onclick="menuClickEvent(this)">Add ...</a></p>
  <div>
    <p><a onclick="menuClickEvent(this)" 
        href="/climbing/myClimbs/myClimbs_add.asp">New entry </a></p>
    <p><a onclick="menuClickEvent(this)" 
        href="/climbing/myClimbs/myClimbs_editWall.asp?a=add">Edit</a></p>
    … more …
  </div>
</div>

Next task: remove inline JavaScript calls

Opinion: Is the Firefox development model really better than Microsoft’s?

Everyone loves bashing Microsoft and preaching the vast superiority of Firefox over IE, particularly its near-perfect implementation of W3C standards. Unfortunately, that might be true as long as you’re doing what the most vocal advocates (the CSS folks) are doing, if you happen to rely on some other “supported” standard, you might find yourself in deep ****.

As my regular readers know, I happened to make a decision to use client-side XSLT a while ago. From the technology standpoint, it was a perfect solution … until Firefox 3 came out. It has so many XSLT-related problems that it’s almost impossible to get the right combination of relevant parameters to have the same XSLT stylesheet working on Firefox, IE, Chrome and the web server (for non-XSLT-capable clients).

OK, one would understand that every major software project has bugs. But it’s hard to understand that so many of the XSLT bugs are untouched after several years. For example: generic ticket describing XSLT result document problems (4 years), HTML-DOM initialization issues (5 years), Firefox crashing when combining XSLT with document.write (6 years), Firebug not working on XSLT-generated pages (1,5 year).

I’ve heard all about limited resources and priorities in my “previous life”, but let’s face the reality: once the motivation (let’s beat IE) wears off and the platform accumulates years of old sins and bad decisions, the development model doesn’t matter. Firefox is becoming no better than IE.

Firefox XSLT errors

When I decided to use server-side XML output and client-side XSLT transformations a while ago, Firefox 2 was the ideal development platform – reliable, well implemented browser with excellent debugging capabilities (Firebug). Since then, the XSLT ignorami contributing code to Firefox have managed to break so many things I simply have to document everything I know to be broken in one place:

On top of everything else, Firebug does not work.

It breaks my heart, but I have to admit that with the rollout of Firefox 3 Internet Explorer 7 does a better job of handling client-side XSLT than Firefox.

Blogger backup works (finally)

I have no problem bashing Google (or anyone else that can't get their act together), but then it's also fair to report when they get something right. They've managed to fix the Blogger backup in the last month or so; now I can successfully back up my large blogs (900 posts, thousands of comments, 6 MB XML file). Great job :)

Firebug does not work on XSLT-translated pages

If you want to use Firebug with Firefox 3 on pages using client-side XSLT transformation, you’re out of luck. Firebug simply does not work; the only way to a half-working environment is the following:

  • Restart the browser
  • Open an XML page with the xml-stylesheet directive.
  • Open a new tab and load a regular page into it.
  • Switch back to the previous tab. Firebug works within the context of the currently loaded page.

What’s really sad is that this has been reported by one of the Firebug developers almost two years ago … and nobody found it important enough to change the bug status from NEW to anything else.

The Blogger software "quality"

I'm constantly amazed by Google's lack of quality (at least in the Blogger area). Let me give you two simple examples:
  • Google has added embedded comment form to Blogger posts. This form works flawlessly with all versions of Firefox on Windows/Linux platforms and fails consistently with IE7 (you have to submit the comment twice). The bug appears in all of my blogs, regardless of when they've been created and what template they use.
  • Google has introduced post ratings months ago. They've immediately got customer feedback that the web pages hang when viewed with Firefox. Five minute long investigation reveals the cause to anyone who's willing to figure it out: Sometimes the AJAX requests they're using take a long time to complete and obviously they're using synchronous XMLHTTPRequest calls in Firefox, blocking the browser.

In both cases, the bugs have been present for months, numerous users have complained (loudly) and nothing has been fixed. Will this affect Google? Probably not. Will I recommend their business applications to my customers? Definitely not.

Just in case you might wonder why I'm yammering in my blog and not complaining to Google: Once they've explicitely asked for our feedback on a new Blogger feature. I've submitted my bug report and never got as much as an acknowledgement ... and the bug that's been bothering me is still there.

Chrome does not hide an element that is not attached to the document

In IE, FF and Opera, the following code hides a DIV element, starts loading the content in it and appends the hidden DIV to the body:

$("<div id='loginDialog'>").hide().load(url).appendTo("body");

In Chrome, the element is created, content is loaded into it, it appears at the end of the document, but it’s not hidden. To make the same code work in Chrome, you have to switch the order of operations: append first, hide later:

$("<div id='loginDialog'>").appendTo("body").load(url).hide();

jQuery interprets NULL parameter to val() call as no parameter

I tried to be smart (no, I was not obfuscating my code) and squeeze the following algorithm into one line of code:

  • Set the field email to the value of cookie user
  • If the cookie user is not present, focus the email field, otherwise focus the pwd field.

The one-liner I (almost) got working is:

if ($("#email").focus().val($.cookies.get("user")).val()) $("#pwd").focus();

The description of how this beast works is left as an exercise for the reader

However, the $.cookies.get function returns NULL if the cookie is not set and the first val call interprets the NULL value as no parameter, returning the current value of the field, not the chainable jQuery object.

Too bad, I had to write two lines of code:

$("#email").focus().val($.cookies.get("user"));
if($("#email").val()) $("#pwd").focus();

Convert Atom-formatted DateTime

The following function converts ATOM (RFC4287) formatted Date/Time string into a VBScript Date variable. You’ll find it useful if you want to process Atom feeds with VBScript/ASP.

Function AtomDateTime(S)
  Dim CompArray,ValueArray,DateVal,TimeString,TimeVal,ZoneSign,ZoneString,I

  CompArray = Split(S,"T")
  If UBound(CompArray) <> 1 Then _
    Err.raise vbObjectError,"AtomDateTime","No 'T' in Atom date/time"
  ValueArray = Split(CompArray(0),"-")
  If UBound(ValueArray) <> 2 Then _
    Err.raise vbObjectError,"AtomDateTime","Atom date part is not a date"
  DateVal = DateSerial(CInt(ValueArray(0)),CInt(ValueArray(1)),CInt(ValueArray(2)))

  TimeString = CompArray(1) : I = InStr(TimeString,"Z") 
  If I > 0 Then
    TimeString = Left(TimeString,I-1)
    TimeVal = GetAtomTime(TimeString)
  Else
    I = InStr(TimeString,"-")
    If I > 0 Then 
      ZoneSign = 1 
    Else
      ZoneSign = -1 : I = InStr(TimeString,"+")
    End If
    If I = 0 Then _
      Err.raise vbObjectError,"AtomDateTime","cannot recognize timezone separator"
    ZoneString = Mid(TimeString,I+1,Len(TimeString))
    TimeString = Left(TimeString,I-1)
    TimeVal = GetAtomTime(TimeString) + ZoneSign * GetAtomTime(ZoneString)
  End If
  AtomDateTime = DateVal + TimeVal
End Function 

The DateTime is converted into GMT time value. You might need to add/subtract your local timezone offset if you want to get local time.

The GetAtomTime function converts the time portion of the DateTime field:

Function GetAtomTime(TS) 
  Dim I : I = InStr(TS,".") : If I > 0 Then TS = Left(TS,I-1)
  GetAtomTime = Timevalue(TS)
End Function

Login to Google Data API

Google Data API has numerous client-side libraries, but not an ASP/VBScript one. Here’s the first routine you need: it authenticates you with the Google API and returns a handle you can use in subsequent calls.

The HTTPCheck is a function that checks the status code before returning to the caller. You could replace if with XRQ.status < 300. You'll find the EncodeFormData function in a previous post.

Dim XRQ ' global XMLHttpRequest object

Function GoogleLogin(UN,Pwd,Svc)
  Dim RQData,I,RT

  GoogleLogin = Null
  RQData = EncodeFormData(Array("Email","Passwd","service","source"), _
    Array(UN,Pwd,Svc,"VBScript-BloggerLibrary-0.1"))

  If Not IsObject(XRQ) Then Set XRQ = CreateObject("Microsoft.XMLHTTP")
  XRQ.open "POST","https://www.google.com/accounts/ClientLogin",false
  XRQ.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
  XRQ.send RQData
  If HTTPCheck(XRQ,"Google login response", _
    "https://www.google.com/accounts/ClientLogin") Then
    RT = XRQ.responseText
    I = InStr(RT,"Auth=")
    If I = 0 Then wr "Google response has no AUTH data" : Exit Function
    RT = Mid(RT,I+5,Len(RT))
    I = InStr(RT,Chr(10)) : If I > 0 Then RT = Left(RT,I-1)
    GoogleLogin = RT
  End If
End Function

The inconsistent consistencies are driving me crazy

Here’s a simple question: what’s wrong with this code?

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:xf="http://www.example.com/common/xslforms">
...
<input type="button" value="X" id="tb_0" onClick="callX(0)" />

Among other things, this is not valid XHTML (as claimed in DOCTYPE) because the onClick attribute should be spelled in all-lowercase (onclick).

Now the trick question: why am I so annoyed by this code? Because it works in IE7, FF2 and FF3 if the server serves HTML to the client and fails only in FF3 if the client performs XSLT transformation using a stylesheet similar to this one:

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="html" encoding="utf-8"
  doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>

<xsl:template match="/">
  <html xmlns:xf="http://www.plezanje.net/common/xslforms">
…
  <input type="button" value="X" id="tb_0" onClick="callX(0)" />
…
</xsl:template>

The ever-more-crazy implementation of XSLT in Firefox will persuade me to:

  • Stop using client-side XSLT transformations or
  • Stop supporting Firefox and recommend everyone to use IE or Chrome.

Generate HTML form data in VBscript

Sometimes you have to post form data in an AJAX call started from server-side ASP script (or WSH script). The following VBScript functions will return well-formed form data that you can use with the application/x-www-form-urlencoded MIME type:

Function URLEncoded(V) ' … private
  Dim CC,I,Enc
  Enc = ""

  For I = 1 To Len(V)
    CC = AscW(Mid(V,I,1))
    If (CC >= 48 And CC < 58) Or (CC >= 64 And CC < 90) Or (CC >= 97 And CC < 124) Or CC = 95 Or CC = 45 Or CC = 46 Then
      Enc = Enc & Mid(V,I,1)
    Else
      Enc = Enc & "%" & Hex(CC)
    End If
  Next
  URLEncoded = Enc
End Function

Function CreateFormField(F,V) ' … private
  CreateFormField = F & "=" & URLEncoded(CStr(V))
End Function  

'
' EncodeFormData: Return form data for a POST request
'
' Input: N – array of form field names
'        V – array of form field values
'
' Return: encoded form data
'
Function EncodeFormData(N,V)
  Dim I
  For I = LBound(N) To UBound(N)
    If I <> LBound(N) Then EncodeFormData = EncodeFormData & "&"
    EncodeFormData = EncodeFormData & CreateFormField(N(I),V(I))
  Next
End Function

How crazy can it get: IE does not set the Referer field if the page was built via client-side XSLT

Some of my web sites rely on client-side XSLT transformations, triggered with the <?xml-stylesheet > processing instruction in the XML document sent by the server. A long time ago I've noticed that some of the utility functions perform differently in IE than in Firefox and finally decided to figure out what's going on. The results are "fascinating": when you click on a link in a page generated with client-side XSLT transformation, IE does not set the Referer: field in the HTTP request. I can only congratulate the coders ... you have an amazing mindset ... not to mention the QA department.