Firefox 4 is rapidly approaching release and there are numerous interface enhancements already included in the current nightlies. One is the addition of AppTabs; sticky tabs that remain at the left of your tab bar that are meant to serve as a place to keep your web “applications” like GMail or Twitter.
There’s still a lot that hasn’t yet determined about AppTabs yet, like how navigation is handled, when a link will open in the AppTab and when in a new tab and so on, but that it will only display the favicons with no title is reasonably certain. Since all your user will see of your website is a favicon it’s important to keep the user up-to-date using only this limited space, for example by showing the number of unread mails as part of the favicon.
This may seem like a difficult task, but thanks to Canvas it’s actually very simple. Assuming you already have a function somewhere in your code that gets notified when the number of new events changes, all you have to do is add code to that function that will create a Canvas, draw the number to it, remove the old favicon, create a new one and finally set it to the url you get from Canvas’ toDataURL.
One by one:
assuming you have a function onNewEvent(newEvents){} that is called with the number of events
function onNewEvent(newEvents){ /* Create a canvas to draw the icon */ var c=document.createElement("canvas"); c.height=c.width=16; var cx=c.getContext("2d"); /* Formatting */ cx.font="18px bold Calibri"; cx.fillStyle="#000"; /* Draw nothing if number is 0, "9+" for 10 or more, otherwise the number */ if(newEvents) cx.fillText(newEvents>9?"9+":newEvents,0,16,16); }
This will create a Canvas with the content we want (you’ll probably want to draw your usual favicon in the background as well and make the text a bit prettier, but this works for now). Now we need to assign it
For some reason setting the href value on an existing link[rel=”icon”] element doesn’t have any effect, so we have to create a new one to replace the existing one. First, let’s remove the old one(s):
var oldicons=document.querySelectorAll( 'link[rel="icon"], link[rel="shortcut icon"]'); for(var i=0;i<oldicons.length;i++) oldicons[i].parentNode.removeChild(oldicons[i]);
And finally we create a new one and attach it to the head.
var newicon=document.createElement("link"); newicon.setAttribute("rel","icon"); newicon.setAttribute("href",c.toDataURL()); document.querySelector("head").appendChild(newicon);
The whole function now looks like this:
function onNewEvent(newEvents){ /* Create a canvas to draw the icon */ var c=document.createElement("canvas"); c.height=c.width=16; var cx=c.getContext("2d"); /* Formatting */ cx.font="18px bold Calibri"; cx.fillStyle="#000"; /* Draw nothing if number is 0, "9+" for 10 or more, otherwise the number */ if(newEvents) cx.fillText(newEvents>9?"9+":newEvents,0,16,16); /* Remove old icons and add node for new one (just setting the href won't work) */ var oldicons=document.querySelectorAll( 'link[rel="icon"], link[rel="shortcut icon"]'); for(var i=0;i<oldicons.length;i++) oldicons[i].parentNode.removeChild(oldicons[i]); var newicon=document.createElement("link"); newicon.setAttribute("rel","icon"); newicon.setAttribute("href",c.toDataURL()); document.querySelector("head").appendChild(newicon); }
That’s all there is to it. No big framework, just a good dozen lines of code and you’re set.
Here’s a bookmarklet that will let you try it on GMail now. It’s Firefox-only since it hooks into GMail using the Gecko-only __defineSetter__ method on the title, but that’s only for the wrapper. The actual code works on any browser as long as it supports Canvas. Just drag this link to your bookmark toolbar, then click it while you’re using GMail (it will persist for your current session, but not if you refresh, restart and so on)
How about
var link = document.createElement(‘link’);
link.type = ‘image/x-icon’;
link.rel = ‘shortcut icon’;
link.href = ‘http://www.stackoverflow.com/favicon.ico’;
document.getElementsByTagName(‘head’)[0].appendChild(link);
The point is to have it include some information, not just set it to a static icon ๐