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.