Archive for December, 2007

sIFR 3 Beta 2: Fire Cracker

posted December 31st, 2007, 75 comments, tagged

As years end nears, neighbourhood kids are playing with fireworks around the house. A nice homage to the second beta of sIFR 3 I’d like to imagine. Feature wise sIFR 3 is now complete, and I think it’s gotten pretty awesome. If you’re trying to decide between sIFR 2 and sIFR 3, sIFR 3 is definitely the better choice.

What is sIFR?

sIFR is meant to replace short passages of plain browser text with text rendered in your typeface of choice, regardless of whether or not your users have that font installed on their systems. It accomplishes this by using a combination of JavaScript, CSS, and Flash, which renders the font. It degrades gracefully if Flash is not present. sIFR 3 is open source and licensed under the CC-GNU LGPL.

What’s new?

Here are the major changes since the last beta:

  • The Flash movie and the JavaScript must be of the same version.
  • Added ratios, which make the loading of the Flash movies less jumpy.
  • sIFR does not work when opened straight from the local filesystem. You must load sIFR from a web server.
  • sIFR movies no longer steal user input focus.
  • When the Flash movie is opened directly, it shows its revision in a bold, italic and normal font.
  • The Flash movie insertion code is equivalent to SWFObject 2.

  • sIFR now supports window resizing.

  • Page zoom in Firefox 3 and IE7 is supported!
  • A workaround has been added for transparent or opaque Flash movies in Firefox/Windows, whose ancestor is floated.
  • A workaround has been added for the loss of Flash variables in Internet Explorer if the innerHTML of an ancestor of a Flash movie is changed.
  • Hover effects tend to get stuck in Flash, added a workaround.
  • Added a custom context menu for links when the hover effect is used.
  • In Internet Explorer, the sIFR Flash movies are hidden when the page unloads. This works around rendering glitches where the old and new movies are briefly shown at the same time.

  • You can specify the font size in pixels, directly from sIFR.replace().

  • You can specify different font sizes within the Flash movie, and they will be relative to the main font size if you specify them with a percentage unit.
  • Added support for bitmap fonts, by rounding the font size to the nearest power-of-eight value.
  • You can now force the text to be displayed on one line.
  • You can disable the pointer cursor (the ‘hand’) inside sIFR.
  • Multiple fonts are supported.

  • You can replace the text inside the sIFR Flash movie.

  • You can change some of the CSS that was applied to the Flash movie.
  • You can get mouse events from the Flash movie.
  • You can tell sIFR to check if the CSS has been applied to the document. This will speed up initialization in Safari and Opera.

  • Opera and Konqueror support has been disabled, because these browsers do not support communication between JavaScript and Flash code.

And there have been many, many more minor improvements. Really, this version rocks!

How Do I Get It?

You can check out a demo of sIFR 3, or simply the most recent version of sIFR 3 from the nightlies. (Note: there are newer versions available than beta 2.) If you want, you can subscribe to a feed for the nigthly releases. Major releases are also announced through the sIFR 3 Announce mailing list.

How Can I Help Out?

First of all, it’s very important to test sIFR in as many scenarios as possible. The easiest way to help out is just to install sIFR on your web site and report any bugs you may find. You can also join the forum or the sIFR 3 Development mailing list. These are also the places to report bugs. Documentation on the wiki could use a lot of improvement. And, of course, a donation is much appreciated.

Support?

Documentation (although, to be honest, it’s not fantastic) can be found on the wiki. The best place to go for support is the forum or the sIFR 3 Development. Please do not post support questions in response to this blog post.

Concluding

I’d like to extend many, many thanks to everybody who filed bug reports, helped testing, responded on the mailing list, improved documentation, spread the word and made a donation. With the year 2008 on the horizon, let’s make it the year of sIFR 3!

(P.S. If you’re curious about sIFR, I’d be more than happy to come give a presentation at your organization!)

Firefox 3, or, technically, Gecko 1.9, comes with support for full page zoom. It works by scaling CSS pixels when the page is rendered – from the perspective of JavaScript or CSS there is no difference between a page zoomed to 200%, 50% or 100%.

I’ve found two ways of detecting the zoom level. One way to detect zoom level changes relies on the fact that percentage values are not zoomed. A percentage value is relative to the viewport width, and thus unaffected by page zoom. If you insert two elements, one with a position in percentages, and one with the same position in pixels, they’ll move apart when the page is zoomed. Find the ratio between the positions of both elements and you’ve got the zoom level. See test case.

The problem with this solution is that it does not detect the zoom level when the page is first loaded.

Another solution I found relies on Flash. Not so much a problem for sIFR, for which I started this little investigation, but not the best solution either. Flash can be configured not to scale with its container page by setting Stage.scaleMode = "noscale";. The Stage.height value gives the height of the Flash movie as its actually rendered by the browser. In other words, this value is not affected by page zoom. The height assigned to the Flash movie <object>, as it exists in the DOM, however, is affected by the zoom level. Simply dividing Stage.height by <object>.height gives the zoom level, even on page load. See test case.

Of course, these two methods are hacks. It would be great if the browser can be queried for the zoom level.

Addendum: I just tested both approaches in Opera and IE 7. The percentages trick works in Opera, but not in IE. IE’s page zoom is quite a hack anyway, so that’s to be expected. The Flash solution works in all browsers, and is far more precise than the percentages approach. Definitely the way forward I’d say!

Browser Wars!

posted December 17th, 2007, 3 comments, tagged

  1. Let browser vendors innovate as fast as they can
  2. With the end-goal of interoperability through standardization
  3. Increasing pressure on other vendors to interoperate, since there are actually four major vendors now, which are all important to most developers

And thereby a better world can be had.

Case in point: Incredibly useful features that used to be IE only, but are now being standardized and implemented by other vendors, such as XMLHTTPRequest, getBoundingClientRect, getClientRects, innerHTML, contentEditable and support for XML/XSLT. Uhm, that basically explains why Xopus is still very much IE oriented – despite all its problems.

Addendum: Proprietary web development with the purpose of standardization is much better than proprietary, period. The latter is inevitable, so what do we do about it?

sIFR 2.0.5 Compatibility Release

posted December 16th, 2007, 23 comments, tagged

sIFR 2′s links do not work with the new Flash Player 9,0,115,0 if a hover color is specified. Additionally, no elements are replaced in Safari 3 if the content type of the XHTML document is application/xhtml+xml. This has been resolved in sIFR 2.0.5.

If you’re using sIFR 2.0.3 or older, and have a hover color specified for links, or are using XHTML documents with the proper content type, you are advised to upgrade immediately. You must upgrade the sifr.js JavaScript code and re-export the Flash movies.

If you’re using sIFR 2.0.4, and are using XHTML documents with the proper content type, you are advised to upgrade immediately. You must upgrade the sifr.js JavaScript code and re-export the Flash movies.

sIFR 3 is not affected by the Flash player issue. Revision 341 is no longer affected by the Safari XHTML issue.

Download sIFR 2.0.5.

sIFR 2.0.6 has been released.

There has been one other change in Flash 9 possibly affecting sIFR users: it will not be possible to use links in a Flash movie loaded from a different domain than the HTML page. I’ve decided not to fix this issue, as the workaround changes the security settings for the sIFR Flash movies. sIFR 3 is not affected by this issue, as it already depends on the workaround.

Detailed Description

In order to support long URLs in Flash 7 and Internet Explorer, when you click on a link in sIFR an ActionScript function is invoked. This function will then cause the browser to follow the link. The anchor element is modified before being passed to the Flash movie to point at asfunction:launchURL,i, where i is an index for the link. Flash 9,0,115,0 still supports clicking on these links, however if a hover color is specified, the link is resolved using an onRelease handler on the parent element of the text field. This handler then tries to follow the link using getURL(). With the new Flash Player it is no longer possible to call an asfunction through getURL(). The code has been modified so that launchURL is called directly.

There’s a serious regression in Safari 3. In XHTML documents the normal properties like document.location, document.cookie and document.body are no longer available. This has been resolved in the WebKit nigthlies, but not in Safari 3.0.4. sIFR 2 had a check for document.body, which I’ve now removed.

See also:

Last Saturday I participated in the Federating Social Networks workshop organized by the fine peeps of Mediamatic (Lab), most especially Ralph. Reduced to its essence, the goal of FSN is to enable websites (“social networks”) to stream data to each other. Rather than pulling data in via feeds and API calls, websites can push data out over an XMPP stream.

One reason social networks may start federating is that feeds don’t scale. Some examples:

  • Blaine Cook of Twitter, who flew over from SF to participate in the workshop, noted that Twitter is getting hundreds of millions of requests through the RSS feed. Apps like Twitterific are limited to one request per client per minute, which is not enough for them to live up to their potential. For Twitter to be able to push tweets to apps such as Twitterific would save them a lot of server load.

  • Jaiku has been blocked a number of times for hitting sites like Last.fm too hard, just to pull in songs. Since Jaiku tries to aggregate a lot of feeds into a lifestream, it’s hitting sites such as Last.fm, Flickr and Twitter constantly. Reversing the aggregation by having Flickr notify Jaiku when a new photo is posted would a) enable Jaiku to display the photo instantly, and b) save Flickr from unnecessary polling.

Of course, federating will have its effect on the business models of these sites as well. For Twitter, one upside of federating is that there’ll be more development around it. Twitterific will be real-time, and will be able to provide many more features. Jaiku will be able to display tweets as if they were jaikus. This may mean that more people start using Twitter, without having to lose their contacts on Jaiku. But, if Jaiku also starts federating, Twitter will be able to display jaikus as if they were tweets. More people may start to use Jaiku rather than Twitter!

What this really means is that boundaries between services start to dissolve. The services will have to be more open, and without lock-in will have to do a better job than its competition. Which, of course, is only good for the end user. And not opening up will only make the services more vulnerable to being out-opened by upstarts.

The protocols to achieve federation are already here today, and Mediamatic is committed to actually get it working. In fact, Mediamatic is in a rather special position where they run several social networks which could greatly benefit from federating, and have obtained a government grant to build a federating system. With Twitter and SixApart also involved – David Recordon of SixApart also flew over from SF – federated social networks have a pretty good chance at becoming reality.

We live in interesting times!

On DOM Load (and CSS, too)

posted December 6th, 2007, 3 comments, tagged ,

The discussion on document load detection is more than two years old. The accepted solution for IE looks pretty much like this:

document.write('<scr'+'ipt defer src="//:" '
  + 'onreadystatechange="if(this.readyState==\'complete\'){dojo._loadInit();}">'
  + '</scr'+'ipt>'

(As you can see I took this from Dojo)

Unfortunately this solution is broken. It relies on the defer attribute, which causes the script to change its readyState to complete after the document has finished loading. defer, however, doesn’t always work correctly. If the innerHTML of a descendant of the body element is changed by an inline script, the script may not be deferred properly. This bug cannot always be reproduced – I’ve seen it occur only a few times while others report it happening on every second page load. However, I did find a way to force its appearance. The bug can be triggered by alert()ing right after changing the innerHTML. See also a test case.

So, without the defer trick, what else can we use to detect DOM load in IE? Diego Perini found a pretty cool solution. If you call document.documentElement.doScroll('left'); before the document has loaded, an exception is thrown. Call it every couple of milliseconds until there’s no exception, and you know the document is ready. Diego has also done a superb job of testing his solution, ensuring that it works as expected.

With IE covered, let’s have a look at document load in other browsers. Mozilla 0.9.4 introduced a DOMContentLoaded event for the document object. Opera 9 also supports this event. Since about two months WebKit supports it as well, but only in the nightly builds. Konqueror is in the same situation, and will support it starting with version 4.0. For WebKit and Konqueror, which do not yet support the DOMContentLoaded event, you can poll the readyState of the document, as explained by Dean Edwards.

We can say that document load is covered (again). However, it isn’t sufficient if your script relies on the CSS being applied. Opera, WebKit and Konqueror load CSS and JavaScript in parallel (all CSS is loaded before being applied, however). This means that the document may have finished loading, and your JavaScript may have executed, before the CSS is fully loaded and applied. sIFR relies on CSS, which means that document load may be too early. Preferably there’d be a CSSApplied event, but in lieu of that, we can detect CSS application ourselves.

The trick is to insert an empty element into the body, which has a style property set in the external style sheet. If you insert this element on document load, and poll every couple of milliseconds until the style property can be retrieved using the computed style, you know that the external style sheet has been applied.

I’ve implemented the hacks discussed in this post in sIFR r339. See also hacks.pageLoad under sifr.js:

function checkStyle() {
  dummy           = dom.create("div");
  dummy.className = CSS_DUMMY;
  dom.getBody().appendChild(dummy);
  pollStyle();
};

function pollStyle() {
  if(dom.getComputedStyle(dummy, 'marginLeft') == '42px') afterStyle();
  else setTimeout(pollStyle, 10);
};

function afterStyle() {
  if(dummy && dummy.parentNode) dummy.parentNode.removeChild(dummy);
  dummy = null;
  fire(null, true);
};

And the CSS:

.sIFR-dummy { 
  width: 0px;
  height: 0px;
  margin-left: 42px;
  z-index: 0;
}