View Full Version : IFRAME events in Safari 2

08-29-2007, 08:55 AM
XSLTProcessor is a JS interface available in Firefox, Opera, and Safari 3 (IE has an ActiveXObject equivalent), which allows for JS to interact with the browser's XSLT engine.

Safari 2 supports XSLT, but not the JS interface. Recently I needed it for Safari 2, so I decided to implement it. Here is some relevant code (implementations for the parameter functions have been removed for brevity):

function XSLTProcessor() {
this.iframe = document.body.appendChild(document.createElement("iframe"));
this.iframe.style.cssText = "position: absolute; left: -10000px;";

XSLTProcessor.prototype.importStylesheet = function(node) {
this.styleSheet = node;

XSLTProcessor.prototype.transformToDocument = function(source) {
var serializer = new XMLSerializer();
var data = "data:application/xml;charset=utf-8," + escape('<?xml version="1.0" encoding="utf-8"?>\n<?xml-stylesheet type="application/xml" href="data:application/xml;charset=utf-8,' + escape('<?xml version="1.0" encoding="utf-8"?>\n' + serializer.serializeToString(this.styleSheet)) + '"?>\n' + serializer.serializeToString(source));
this.iframe.setAttribute("src", data);

// Wait until transformation is done

return this.iframe.contentDocument;

The single comment most of the way down is the only thing holding the implementation up. As far as I can tell, Safari doesn't fire the onload event on an iframe if an XML document was loaded (instead of an HTML document). I've attempted while(something) continue; (where something might be a check for an element that only occurs in a default location which can be set in the constructor, or simple existence of contentDocument), and at best, that just eats the CPU and prevents the transform from ever occurring (but usually just fails to work anyway). My testing involves a fairly simple XSLT transform, so I can usually wait half a second can get the transformed document, but that is not a real solution.

As I see it, the only way to accomplish this using my iframe+data: trick is to figure out how to determine when it finishes (asynchronously), then pretend it is synchronous by forcing a wait, OR some other novel method using the data: uri trick.

Ideally my implementation matches Firefox's/Opera's (in its synchrosity)... any input would be much appreciated. :)

08-31-2007, 07:17 PM
I am going to bump this once and only once in case it got buried. I do apologize.

08-31-2007, 11:36 PM
Actually, I can't think of making this work synchronously cross browsers - you can't busy wait since the code block is executed by run-to-completion. The only way I can think of that might *LOOK* synchronised but really isn't is if you do a CPS transformation of the code and send the cont to some asynch handler.

There is one venue that I'd investigate though: Throwing an exception, somehow (and I have no idea how this could even be achieved) schedule the completion from there using some asynch handler, and simply delay the call.

In JS1.7 there is another possibility: Using yield and an asynch handler.

The first way is clunky and requires the code structure to be changed. The second, I can't think of a way to resume the execution. The third, well, doesn't work in your target browser.