Entries tagged ‘sifr’
sIFR 2.0 – 2.0.5 failed to detect the Flash 10 player, and therefore falls back to normal HTML text. This had previously been resolved in sIFR 2.0.6, however an issue remained with Safari. There is a second Flash version detection, which had not been fixed, and resulted in transparency support being disabled for Safari browsers with Flash 10 installed.
If you are upgrading from sIFR 2.0.4 or older, you must upgrade the sifr.js JavaScript file and re-export your sIFR Flash movies using the sifr.fla file from sIFR 2.0.7.
If you are upgrading from sIFR 2.0.5 or 2.0.6, you must upgrade the sifr.js JavaScript file.
Update, December 1st, 2008: A new sifr-cs3-and-up.fla file has been added to the download. Use this file if you’re using Flash CS3 or later. Find out more.
Detailed Description
sIFR 2 uses the same Flash detection that was originally used in its precursor, IFR, back in 2004. Unfortunately this detection script only expected single digit Flash versions, so it fails to detect Flash 10. This has been fixed in sIFR 2.0.6. However, I missed a second Flash version detection, which was used to check for transparency support in Safari browsers. Back in the day, Safari did not support transparency with Flash 6, so an explicit check for Flash 7 was added. The second version detection failed to detect Flash 10, disabling transparency support under Safari.
Thanks to Giancarlo Gomez for originally pointing out the problem with the Flash detection, and Marco Della Pina for pointing out the Safari problem.
Unfortunately, sIFR 2.0.6 did not resolve all issues. Please use sIFR 2.0.7 instead.
sIFR 2 fails to detect the Flash 10 player, and therefore falls back to normal HTML text. This has been resolved in sIFR 2.0.6.
If you are upgrading from sIFR 2.0.4 or older, you must upgrade the sifr.js JavaScript file and re-export your sIFR Flash movies using the sifr.fla file from sIFR 2.0.6.
If you are upgrading from sIFR 2.0.5, you must upgrade the sifr.js JavaScript file.
Detailed Description
sIFR 2 uses the same Flash detection that was originally used in its precursor, IFR, back in 2004. Unfortunately this detection script only expected single digit Flash versions, so it fails to detect Flash 10. This has been fixed in sIFR 2.0.6. Thanks to Giancarlo Gomez for pointing out the problem with the Flash detection.
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.
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:
sIFR 2.0.5 has been released. Please upgrade to sIFR 2.0.5.
Yesterday, a security vulnerability was found in sIFR 2 and 3. Malicious websites can trick visitors into running JavaScript code on domains hosting sIFR movies. No exploits are known. If you are currently using sIFR 2, you are advised to update to version 2.0.3.
You’ll need to update the sifr.js file and re-export the sIFR movies.
Detailed description
sIFR passes the text it has to render to the Flash movie using Flash variables. Normally these variables are specified using a flashvars parameter, however they can also be passed using the query string. Malicious websites can craft an iframe which points to a sIFR movie on the target domain. An HTML link to some JavaScript code can be passed to the movie through the query string. When a visitor of the malicious website clicks on the link, the code is run on the domain the movie resides. Vulnerable browsers are Firefox, Safari, Opera and Netscape. This specific attack does not work in Internet Explorer. An alternative attack is to load the movie directly or in a popup window, this does work in Internet Explorer.
sIFR 2.0.3 prevents this attack by not rendering any content that is passed through the query string. Credit goes to Arseny Vesnin for finding the vulnerability.
Other changes since version 2.0.2
- sIFR has been disabled for Safari 1.0.
- If the
innerHTMLof an element containing a sIFR movie changes, the sIFR movie will fail to render. Upgrade to sIFR 3 to fix this.
sIFR 2.0.5 has been released. Please upgrade to sIFR 2.0.5.
sIFR 3 Revision 278 has been released. Please upgrade to sIFR 3 Revision 278.
Just in time for Christmas, I present you a new sIFR release! It’s been a long time coming but with this release I feel sIFR 3 is ready for widespread deployment. If you’re unfamiliar with sIFR, the obligatory introduction paragraph goes like this:
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.
Compared to sIFR 2 the new version is radically different. Backwards compatibility has been broken, but that’s okay since deployment is now ridiculously easy. There’s great control over how the text is rendered inside the Flash movie: you can easily use bold and italics together, or use different colors. There’s support for leading, kerning and opacity, filters, blend modes and anti-aliasing.
The biggest changes from the alpha release are:
- No more Flash 7 support. This led to a simplification of the code base and made sIFR easier to deploy.
- No more compatibility mode. Supported browsers are Internet Explorer 6+, Firefox 1.0+, Safari 2.0+, Opera 8+ and Konqueror 3.5.6 (due in Januari) .
- Improved Flash detection.
- Improved rendering in Internet Explorer.
- Firefox and Internet Explorer will now replace the elements before the page has finished loading. No need to put JavaScript inside the
bodytag. - Fine-grained tuning of the text position inside the Flash movie.
- Callback handlers to modify the content being replaced, the CSS, and the end result.
- Support for text transformation, including capitalize.
- Domain validation on the client side, useful for example to stop sIFR from running when the page is being translated by Google Translator.
- Various bug fixes.
Documentation has improved, too. There’s now a simple introduction tutorial and the configuration settings and methods are properly documented. No doubt this still needs work, and that’s exactly why the documentation takes the form of a wiki. If you see improvements, feel free to make them.
As I said before, I really feel this version is fit for widespread use. However, it’s still a beta so please keep track of developments, for example by subscribing to the mailing list. If you’re using sIFR please consider making a donation, especially if you’re a company. Here’s a nice button to click:
sIFR 3 is open source and licensed under the CC-GNU LGPL. Check out the demo and go download it! If you want to keep track of newer developments, check out the nightlies. Anything from revision 199 is new. And finally, 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.
sIFR 3 Revision 278 has been released. Please upgrade to sIFR 3 Revision 278.
- View the demo.
- Download sIFR 3 beta 1.
- For support, check out the forum.
sIFR 2.0.5 has been released. Please upgrade to sIFR 2.0.5.
I’ve just released sIFR 2.0.2, which is a maintenance release for the problems caused by the “Eolas patch”. JavaScript changes from version 2.0.1 are:
- Problems due to the Eolas related modifications to IE should be solved. Thanks to Christian Welzel for testing!
- A problem where the CSS class name foo-bar would match foo has been solved.
- Problems where the browser reports an alien user agent (like GoogleBot) have been solved.
- Improper detection of Flash transparency support in OmniWeb 5.1 have been solved.
- You should now be able to export sIFR as Flash 8.
CSS (in sIFR-screen.css) changes are:
* No more object tab obscuring the text when AdBlock is being used.
There is still no insight into what is causing these problems, so please deploy this patch to ensure everyone can see the headlines. You’ll only have to replace the JavaScript file (make sure not to override your configuration) and add a CSS rule for the AdBlock workaround.
sIFR 2.0.5 has been released. Please upgrade to sIFR 2.0.5.
While working with Microsoft to fix the mentioned problems with sIFR and the Eolas patch (the security updates for Internet Explorer released on April 11th) I’ve also been working on a patch for sIFR itself. But before I get to that, some updates on the problem:
- Everyone who reported the problem and whom I have asked to verify, is using either Flash MX 2004 or the Flash 8 editor.
- This might mean that the problem is related to the editor being installed
- Or only people with the editor take the trouble to contact me.
- Reinstalling Flash fixes the issue.
- Using
<object>instead of<embed>prevents the issue.
It still is not clear what the exact conditions are for the problem to occur, but most likely it’ll be solved when people update their Flash players… in a few years, that is. Therefore, the patch to sIFR.
This patch, bringing sIFR to version 2.0.2 has the following fixes:
- Problems due to the Eolas related modifications to IE should be solved. Thanks to Christian Welzel for testing!
- A problem where the CSS class name
foo-barwould matchfoohas been solved. - Problems where the browser reports an alien user agent (like
GoogleBot) have been solved. - Improper detection of Flash transparency support in OmniWeb 5.1 have been solved.
- You should now be able to export sIFR as Flash 8.
A test version of the patch is available: Download sIFR 2.0.2 TEST.
Please let me know how this version functions. Nothing should be broken in other browsers, but of course you never know. Once I’ve had enough feedback I’ll officially release the patch.
sIFR 2.0.2 is out now
After Microsoft rolled out their Eolas patch I got a few reports about sIFR not working correctly. As sIFR is a script which creates the Flash movies there shouldn’t be any issues, but unfortunately that is not the case.
There are two problems, one is easy to fix and is the result of extra steps taken in the deployement of sIFR. The other seems to be a system issue, and as such is harder to fix.
First, the easy problem. Using the sIFR code in the page itself causes the sIFR Flash movies to require activation:
You cannot write script elements inline with the main HTML page to load your control externally. If the script is written inline programmatically, for example with the writeln function, the loaded control will behave as if it was loaded by the HTML document itself and will require activation.
Using sIFR inline is not advised at all, nor shown in any demos or documentation, so I don’t expect this to be a problem. However, when the sIFR code is evaluated using eval(), IE thinks the code is inline. This causes the need for activation. sIFR is not distributed with eval() evaluation of it’s source code, so if you are using a version which is, please dowload and use the official release.
Testcases for this problem are available.
The other problem is that, for some users, the patch broke sIFR rendering for both the 2.0 version as the sIFR 3 demo. Instead of showing the Flash text, a non-loaded image icon would be shown. I do not know what causes this issue, but I’m in contact with Microsoft about it. I cannot replicate the problem myself, but there have been six reports. If you see this problem, please contact me with the following information about your system: OS, Flash version, used Flash versions in the past, installed IE 7 betas, installed Eolas-patches (aside from the one rolled out in Windows Update).
I have heard that reinstalling the Flash Player fixes the issue. However, I would greatly appreciate it if you could hold off on doing this until Microsoft has more insight in what is causing the problem. Thanks!
One of the advantages of sIFR is that the Flash files are cached on the client, saving bandwith. Except, of course, when they aren’t cached, as was pointed out on the sIFR forum. Luckily a solution was hinted at by Marc van den Dobbelsteen from Webbforce. Requesting the Flash file using a document.write() call fixes the problem. Thus, I set out on a journey through seemingly endless browser reloads and cache emptying…
Diagnosing the problem
When sIFR starts replacing elements it adds Flash movies to the document in a very short time. The browser needs to request these movies, which often have the same source. Testcases show that both Internet Explorer and Safari will stupidly request the same source for each movie, until the first request comes back. Upon reload (when the source is in the cache) no further requests are made.
Here are some log files:
# IE
“GET flash-caching/no-caching.html HTTP/1.1″ 200 511
“GET flash-caching/test.swf HTTP/1.1″ 200 8249
“GET flash-caching/test.swf HTTP/1.1″ 206 8249
“GET flash-caching/test.swf HTTP/1.1″ 200 8249
“GET flash-caching/test.swf HTTP/1.1″ 206 8249
“GET flash-caching/test.swf HTTP/1.1″ 200 8249
“GET flash-caching/test.swf HTTP/1.1″ 200 8249
“GET flash-caching/test.swf HTTP/1.1″ 200 8249
What’s interesting here is the 206 response. It seems IE isn’t happy with requesting the file and asks for it again, but this time it wants a partial file. For the five equal Flash elements on the page, seven requests are made.
# Safari 417.9.2
“GET flash-caching/no-caching.html HTTP/1.1″ 200 511
“GET flash-caching/test.swf HTTP/1.1″ 200 8249
“GET flash-caching/test.swf HTTP/1.1″ 200 8249
“GET flash-caching/test.swf HTTP/1.1″ 200 8249
“GET flash-caching/test.swf HTTP/1.1″ 200 8249
“GET flash-caching/test.swf HTTP/1.1″ 200 8249
Safari is a bit smarter, but still requests the same file five times.
Fixing the problem
Loading the Flash file once, before other requests are made, stops the user agent from requesting it too many times. This gives us a clue for fixing the problem. In Safari we request it through a script in the head:
new Image().src = 'test.swf';
But alas, this doesn’t work in IE. Here’s the IE code:
var head = document.getElementsByTagName('head')[0];
var node = document.createElement('embed');
head.appendChild(node);
node.setAttribute('src', 'test.swf');
You might want to remove the embed element later on, just to keep the DOM tidy. Also note that to be certain the file has been loaded, you need to load the other Flash movies after onload.
Now we have the following in our logs:
# Safari 417.9.2 Prefetching
“GET flash-caching/caching-safari.html HTTP/1.1″ 200 1014
“GET flash-caching/test.swf HTTP/1.1″ 200 8249# IE Prefetching
“GET flash-caching/caching-iexplore.html HTTP/1.1″ 200 1057
“GET flash-caching/test.swf HTTP/1.1″ 200 8249
“GET flash-caching/test.swf HTTP/1.1″ 206 8249
That’s quite an improvement! Safari requests the file exactly once, while IE is stubborn and requests it twice.
Implementing the fix in sIFR 3
A slightly more specific version of the code above is used in sIFR 3. You can pre-fetch files using sIFR.prefetch('one.swf', 'two.swf', 'etc.swf'). This works pretty well, except that in Internet Explorer sIFR is allowed to kick in before the document has fully loaded.
A trade-off has to be made. Let’s say that the first time the website is loaded, sIFR is not allowed to kick in before the document is fully loaded. The next time it is, since the files no longer have to be pre-fetched. Determining whether the site is loaded for the first time is done through a session cookie. This brings us to the following situations:
- The user visits the site for the first time. The Flash movies are pre-fetched and sIFR will only kick in on page load.
- The user navigates to another page on the site. No pre-fetching takes place, the Flash movies are loaded from cache and sIFR kicks in right away.
- The user has cookies disabled. The Flash movies are prefetched for every page load, but will come from the cache after the first load. Depending on the load time for the page there are extraneous requests for the first load. sIFR does kick in right away.
Of course the cookie path and the use of the cookie itself can be configured.
This fix makes sIFR respond faster and saves bandwidth. And of course, Internet Explorer and Safari can be are a pain to work with.
This problem is now known as bug 8659 in the OpenDarwin bug tracker.
As I’ll have to focus on course-work and money-making-work in the next few weeks here is a feature list for sIFR 3. Of course, when something turns out to be too hard to implement, it’ll be removed from the list. Don’t take it for granted!
- Better and easier font sizing, as explained in Font Sizing with sIFR.
- FlashCSS: This lets you use multiple colors and different text styles in general. It also aids with link styling. Todd Dominey has a list of supported properties.
- Controlling kerning, leading and line-height.
- Font resizing.
- Better FlashBlock support (actually this’ll be a side-effect of the font resizing).
- Possibility to ignore specific elements during replacement.
- Modification of the content passed to sIFR.
- Pixel fonts.
- Flash 8 filters.
- Background images inside the Flash.
sIFR itself will be easier to use, and there’ll be a number of small fixes for edge-cases. Speed improvements are high on the list as well, obviously.
Font sizing is the most difficult part of using sIFR. In this post, I’ll discuss how the algorithm in sIFR 2 works, or rather, why it doesn’t work as well as originally intended. Coincidentally, this makes this post an excellent tutorial for font tuning in sIFR 2. We’ll also look at how things will be improved with sIFR 3.
sIFR 2
The algorithm used by sIFR 2 is relatively simple:
- Take the width and height of the element you want to replace.
- Create a Flash movie which uses these dimensions.
- Increase the font size from 6 pixels, pixel by pixel, while rendering the text, until the height of the text is larger than the Flash movie.
- Render the font with a size one pixel smaller than obtained in (3).
Unfortunately this doesn’t quite work. First of all: the font used in the Flash movie may be wider or smaller than the font used in the HTML. Let’s say the font is wider, what will happen then is:
- Because the font is wider, it will wrap to a new line earlier than the HTML font would.
- This allows for the possibility that the text will reach the allowed height earlier, resulting in a smaller font size (see point 3 above).
A way to deal with this is to set the letter-spacing of the HTML text so the font appears to be wider, having the effect of giving it the same width as the Flash font. This works, assuming that there are no other factors influencing the width and height of the text, such as (unintentionally) using different fonts on different user machines. Default browser settings for CSS properties like font-size or letter-spacing can be of influence as well.
In short, achieving cross-browser and cross-platform consistency of the width and height of the text, while taking into account the width of the font used, can be very, very hard.
sIFR 3
In sIFR 3, things will work a little different. For starters, the font size is no longer determined by the width and height of the text. Instead I’ve figured out a way to derive the font size from CSS. Here is a short version of the rendering algorithm employed by sIFR 3:
- Determine font size and the number of lines the text takes up.
- Create a Flash movie using the width and height of the text, these can be changed later.
- Render the text.
- If the text is wider than the allowed width, try wrapping it to the next (or a new) line.
- If a single word is causing the text to be too wide, resize the movie.
- If the text now requires more lines, resize the movie.
Resizing the movies requires Flash to talk to the JavaScript code in the website. Since we’ve dropped Flash 6 support, this has now become possible.
Specifying the desired font size in Flash is quite easy as well. All it takes is two properties!
.sIFR-hasFlash h1 {
font-size: 12pt;
line-height: 1em;
}
Why the line-height? sIFR uses the line-height and the height of the element itself to calculate how many lines the text uses. By using line-height: 1em; we ensure it has the same value as the font size. As Eric Meyer said:
(…) for line-height, em-based values are calculated using the computed font-size of the element itself. I declared the font-size directly, so we know its computed size in pixels.
It also turns out that if you specify line-height in ems, and don’t specify it in the descendent elements, they will have the same line-height:
So that computed value (…) is what’s passed on to the descendent elements. (These) elements will inherit (the same)
line-heightvalue. End of story. They don’t change it based on their own font sizes; in fact, they don’t change it at all (sic).
Concluding
sIFR 3 will bring easier font tuning, as well as other features I’ll talk about later. You can see the original font tuning experiments, as well as a demo of the current stable SVN export.
Some time ago Mike and I asked you what features you wanted to see in sIFR 3. While we haven’t defined the exact list of features for the new version it has become time to look into the future to see where sIFR is heading.
As you probably know Mike is now the CEO of Newsvine, and as such he’s pretty occupied. The result of this is that the actual development of sIFR 3 is resting fully on my shoulders. Since I’m no super hero, I’ve been thinking about how the development process should be approached and how you can help with it.
sIFR Wants You
sIFR is meant to work in as many browsers as possible. Being a fully degradable add-on, it should not break sites when a browser has trouble supporting it. To accomplish this goal a lot of testing is needed. Much more testing than I have machines or time for. To speed up and improve with this testing we’re hoping for the user-base to lend a hand. Yes, sIFR wants you.
A mailing-list has been set up to aid in this process. After every significant iteration of the code you’ll be notified through this list of new tests. The tests will mostly be automated, aside from the occasional human verification. We’re hoping to get confirmations from two or three people for each browser and browser version we are supporting (more about that in a later post).
The list will also be used to discuss the way sIFR works itself. Here you can think of the tuning process or how to provide fallback for Flash transparency. sIFR is not going to be “designed by committee” however. While we greatly value your input, at the end of the day it’s going to be our call.
Time
Just as Mike is busy, so am I. Currently I’m studying Computer Science at the University of Twente and I also have to earn some money. If you have an interest in seeing sIFR developed faster please consider donating (by clicking on the Make a Donation
button on the right) or hiring me to work on sIFR.
The Future
The future of sIFR is bright. With the advent and acceptance of newer browsers it has become possible to ease the use of sIFR. The release of the new Flash 8 gives us more power, and also means we’re letting go of Flash 6. Good stuff is on it’s way, and I hope you’re in for a ride. Again, please sign up for the mailing-list and thanks in advance for your support.
sIFR 2.0 is out! This has been my biggest project in the past months. I’ve spent hours upon hours tweaking and tuning the code to make it as easy to use as possible and to make it work in virtually all browsers out there. It’s been a great experience, and I’ve learned a lot more about providing support, promoting an open source project and (unfortunately) cross-browser issues. Heck, we even got Slashdotted!
During the development I worked closely together with Mike, who is a great guy to work with, he’s smart, pragmatic and he’s showed a lot of patience when we were debugging sIFR via IM. As far as I can tell there’s only one bad thing about him, which is that he’s a bit groggy in the mornings. Since I’m nine hours ahead of him, you can guess what time of the day we usually discussed things…
I’d like to thank everyone who I recruted to test various incarnations of the code, in various browsers. I don’t remember all your names, but you know who you are! In special, though, I’d like to thank Joen Asmussen for his article on sIFR, Andrew Hume for How and when to use sIFR and Stephanie Sullivan, who has been a great help improving the documentation.
And of course a huge thanks to everyone else who used and/or promoted sIFR. Thanks!
Now that we’ve reached the end of the 2.0 cycle, perhaps it’s a good idea to look into the future. I expect sIFR to become a bigger influence in webdesign in the coming months and I hope it’ll accelerate the design of a system which will allow designers to load fonts via CSS. In any case, we’ll make sure sIFR continues to work in future browser versions.
Again, thanks for this wonderful experience.
This is an introductory tutorial to the sIFR Explained series, covering basic JavaScript (and programming) concepts — some knowledge of JavaScript, like knowing how to define functions, is required though. It’ll be updated from time to time when more background information is necessary. Here we go.
Anonymous Functions
An anonymous function is a function without a name. This is an anonymous function [1]:
function(msg){ alert(msg); }("hello world");
What is happening here is that the function is defined: function(msg){ alert(msg); } and executed immediately: ("hello world").
This isn’t an anonymous function:
function foo(msg){ alert(msg); };
foo("hello world");
Nor is this:
var foo = function(msg){ alert(msg); };
foo("hello world");
In general anonymous functions are used to execute code which only needs to be executed once. This is the way it is used in sIFR. A side effect which occurs in the sIFR code is the creation of closures.
Scope, the scope chain and closures
But before we get into closures, something about scope. Every JavaScript expression is surrounded in a scope. The scope contains what is available to the expression. When you define a new function, the body of this function exists in a new scope. For example:
function foo(){
var msg = "hello world";
alert(msg);
};
foo();
Here alert(msg); works, because msg is defined in the same scope as in which alert is called.
Deep down in the JavaScript interpreter the scope is represented as a call object. This object contains all the variables which have been defined in the scope that the call object represents. When a new scope is created, it’s call object is linked to the call object of the scope it was created in. This creates a scope chain.
This phenomenon is best explained through an example. In JavaScript the window object is the global scope. This is the highest scope in the scope chain. If we create a new function in the global scope the scope of this function will be chained to the window object:
var msg = "hello world";
function foo(){
alert(msg);
};
foo();
Now, if you call foo, it’ll alert hello world
! But how does it know the value of msg, which wasn’t defined in the function body foo? It turns out that if the JavaScript interpreter can’t find a variable in it’s current scope, it’ll go up the scope chain and searches the parent scope until it finds the variable. In our case it finds msg in global scope.
You can also create a scope chain by nesting functions:
function foo(){
var msg = "hello world";
function bar(){
alert(msg);
};
bar();
};
foo();
Now, if you call foo, it’ll define bar and execute it immediately afterwards. And as expected it’ll alert hello world
.
When a nested function has access to the scope of it’s parent function, it is called a closure. sIFR relies quite heavily on closures.
At ths point you might want to read Variable scoping gotchas from Scott Andrew for more information about defining variables in JavaScript.
Footnotes
[1]: I’m not really sure why you’d want to write an anonymous function to alert `”hello world”`, but it’s just an example!
This is a series about how the JavaScript code in sIFR works. What tricks were used, what are the powerful concepts, and what are the browser hacks. It’s an interesting read, in which you’ll dive into some complicated JavaScript code.
Before we get started though, you might want to read the terminology tutorial which will give you insight in the wonders of closures, scopes and all that fancy stuff.
Enjoy!
For sIFR RC3 I wrote a handy little piece of code which allows users to use named arguments in their JavaScript code. For example, if you have a function foo which takes five arguments, and you only need to set the first and the last, this can be quite cumbersome:
function foo(one, two, three, four, five){
// do something
};
// let's call foo() with only the first and last argument
foo("hello", null, null, null, "world");
sIFR takes thirtheen arguments, a lot of which are optional. As you can hopefully understand using named arguments is lots easier.
Interlude – For the True JavaScript Hacker
If you’re really interested in how all this all works, and how you can implement it in your own scripts… please be patient. I still have to write about the inner workings of my named arguments implementation. Sorry!
Syntax & Placement
In order for named arguments to work you need to pass a special construct to the function. The syntax of this construct is like this:
named({
name : value,
name : value
})
named({ is the beginning of the construct. name : value, is the syntax you need for each argument. name is the name of the argument and value is of course the value. You end the construct with }).
Due to a bug in Internet Explorer and Opera you have to be careful not to end the last argument with a comma. There will be a JavaScript error and the code will break.
By convention you pass this construct to the function as the last argument.
Example
Let’s look at the function foo from earlier in this article. Using named arguments the function call will look like this:
foo(named({one : "hello", five : "world"}));
Much easier, eh?
Here’s an example where we pass some other arguments to the function before the construct:
foo("the", "ocean", named({three : "breathes", five : "salty"}));
Here we passed on the arguments one, two, three and five to the function.
Applying it to sIFR
sIFR takes the following arguments (in this order): sSelector, sFlashSrc, sColor, sLinkColor, sHoverColor, sBgColor, nPaddingTop, nPaddingRight, nPaddingBottom, nPaddingLeft, sFlashVars, sCase, sWmode
You can find out what these arguments do in the readme.txt in the download. The names of the arguments above are the same as those which you use in the named arguments construct. For example:
sIFR.replaceElement("h1", "./vandenkeere.swf", named({sColor : "#000", sCase : "upper"}));
Here we passed on the arguments sSelector, sFlashSrc, sColor and sCase to the sIFR.replaceElement function.
Usage Ideas
There are more ways named arguments can simplify your (sIFR) life. You could also store the construct in a variable and use it as a template:
if(typeof sIFR == "function"){
var template = named({sFlashSrc : "./vandenkeere.swf", sColor : "#000", sCase : "upper"});
sIFR.replaceElement("h1", template);
sIFR.replaceElement("h2", template);
};
No doubt more things are possible, but I’m leaving that to your imagination.
Download and Licensing
Just as sIFR the named arguments code is licensed under the CC-GNU LGPL. You can also download the source.
And Finally
If you have any questions about this article or the code, please contact me.
For now, please see the explanation for sIFR users.
Version Update – Konqueror Crazyness
As of today (Jan. 4, 2005) Named Arguments is at version 1.0.1. A bug was discovered where browsers based on an old Apple WebKit / Konqueror version (WebKit v85) would throw a JavaScript error:
Anonymous function hack: eating identifier named_Arguments
Anonymous function hack: eating identifier named_extract
This was caused by naming an anonymous function:
named.Arguments = function named_Arguments(oArgs){
Removing the name and the script worked again:
named.Arguments = function(oArgs){
I searched for the error message in Google and found what looks like the source code for the Konqueror JavaScript engine… and I quote:
00524 // Lookup for keyword failed, means this is an identifier
00525 // Apply anonymous-function hack below (eat the identifier)
00526 if (eatNextIdentifier) {
00527 eatNextIdentifier = false;
00528 #ifdef KJS_VERBOSE
00529 UString debugstr(buffer16, pos16); fprintf(stderr,"Anonymous function hack: eating identifier %s\n",debugstr.ascii());
00530 #endif
Also note that I had to apply a workaround earlier because the Konqueror JavaScript engine doesn’t deal very well with constructors for classes:
named.Arguments.prototype.constructor = named.Arguments;
Things like this make we want to throw the computer out of the window – luckily Mike found the bug, so I had no reason to throw my computer out of the window
I got a question today on where you should put the replacement code for sIFR. Here’s that e-mail, with reply:
cheekygeek wrote:
Mark, I’ve asked this on a couple blogs, but forgot which ones so don’t know if I got an answer.
The replacement code for sIFR can go at the bottom of the page OR in the sifr.js file. Is there a rendering-speed improvement to putting it one place or the other? I wonder if you could list the most important factors in getting the sIFR headlines to render the fastest (small/few font.swfs being used, etc.)
Also, does it matter how you call the sifr.js file (speedwise?)
Thanks!
Hey,
The explanation was covered in an earlier version I believe, but it
works like this: if you put the replacement code in the JavaScript file,
it’ll be executed on onload or when you call sIFR(). If you put
the replacement code in the body, it’ll be executed immediately.
Effectively, this means that you could put the replacement code in the
JavaScript and call sIFR() in the body. It won’t make any difference.
The reason there are two methods to replace elements in sIFR is that the onload event is only fired when the page has fully loaded — including all images and other external files. This can take much longer than the actual rendering of the page, so replacing inside the body will make sIFR look faster.
There is a downside to this, however. Elements which haven’t been rendered correctly (imagine an image without width and height attributes) can affect the layout, and in effect (no pun intended!) this can affect the rendering of replaced elements (as these are based on the dimensions of the original elements).
Also, in Safari and in Gecko browsers in XML mode the page isn’t rendered at the moment you would normally replace the elements in the body. For these browsers the replacement is postponed until onload.
Take care,
- Mark