Posts Tagged ‘XML’

* Surfin’ Safari

Posted on October 9th, 2008 by Dave Johnson. Filed under AJAX, CSS, JavaScript, XML, completeui, quirks, safari.


For the past little while I have been busy fixing up Complete UI to work in Safari. The big problem for us in getting Complete UI working in the WebKit powered browser was that there was no client side XSLT JavaScript API until Safari 3.

So there were a few things I had to update to get things all working properly - and this more or less applies to Chrome now as well but I need to check on a few things.

XMLDocument::selectNodes

The first problem I came across was using the XMLDocument::selectNodes method. To get selectNodes working I had to implement my own NamespaceResolver which is usually handled for you by the browser.

I had to change the call to the XMLDocument:evaluate method a bit to look like this:

var oResult = this.evaluate(
  sExpr,
  (oContextNode?oContextNode:this),
  new MyNSResolver(),
  XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
  null);

Where the MyNSResolver class essentially implements the lookupNamespaceURI method through a switch statement returning the appropriate URI for the specified namespace prefix. Pretty easy but kinda annoying to figure out!


function MyNSResolver() {};
MyNSResolver.prototype.lookupNamespaceURI = function(prefix) {
  switch (prefix) {
    case "xsl":
      return "http://www.w3.org/1999/XSL/Transform";
      break;
    case "ntb":
      return "http://www.nitobi.com";
      break;
    default:
      return null;
  }
}

XSLT Transformations

Then there was the actual act of performing an XSLT transformation. Doing the transformations was fine but getting the output node or string from the transformations - depending on if the <xsl:output /> was text, html or xml - was rather different than both Firefox and Internet Explorer. Go figure.

For transforming to an XMLDocument here is what I found to be the output of an XML transformation for the various output methods.

Text:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title></title>
  </head>
  <body>
    <pre>innerText</pre>
  </body>
</html>

XML:

<output>innerText</output>

HTML:

<html>
  <body>
    <output>innerText</output>
  </body>
</html>

XSLT Parameters

There is also one difference in how the Safari XSLT processor deals with parameters. Rather than casting true / false to 1 / 0 the Safari XSLT processor does not recognize true or false values and requires the inputs to be 1 / 0. I have started setting all my XSLT params like this:


oXsltProc.addParameter("paramName", val+0, "");

Events and Focus

There were some other small issues that I came across regarding implementing rich keyboard navigation and events in general.

For example, in our Grid component I had to change the HTML element that we used to “focus” the Grid so that we could capture key presses from a <DIV> to an <INPUT>. Apparently you can’t call Element:focus on a <DIV> element from JavaScript but you can on an <INPUT> (even with a tabIndex set but I try to avoid those for accessibility reasons anyhow).

However, that was not my only problem with keyboard navigation. The other problem was that the focusable element (the newly created <INPUT> in this case) was still not getting focus due to a small code snippet like this:


oMyInput.focus();
cancelEvent(evt);

That second line where I cancel the event (wrapped nicely in a cross browser library call) somehow prevents the <INPUT> from getting the focus. Never figured out a workaround aside from a browser check before calling cancelEvent.

CSS

Finally, in some of our components we also generate CSS using XSTL and dynamically insert it into the page. For example, the developer defined column widths in a Grid produce dynamically generated CSS. However, WebKit does not seem to support the bulk creation of stylesheets neither using the document.createStylesheet method of Internet Explorer nor the hacky way of doing in Firefox by creating a <STYLE&gt element and setting the innerText. Instead Safari requires that you use the uber slow DOM API for adding rules to stylesheets :(

Miscellany

You will often see the “xml namespace prefix mapped to wrong URI” error when working with XSLT in Safari.

Be careful that you are using double quotes in your XSLT for attributes etc and only use single quotes in attribute values.

Of course you also have to be very careful about the nodes that you are transforming / selecting as you are also likely to get the “WRONG_DOCUMENT_ERR” fairly frequently.

Oh yah and depending on the application expect a lot of random “Stack overflow” errors!

Tags: , , , , , , , .