Update: This doesn’t work as intended anymore. A new article offering an alternative method that works for modern Firefox versions has been posted here.
Note: this is tested only in Firefox. It works perfectly there, but in other browsers you may either get the icon only temporary (if the bookmark icon cache is part of the normal cache) or no icon at all. However it won’t break anything anywhere, so that’s no reason to not use it.
I investigated this a while back and it’s really quite simple, but apparently few people are aware of it:
First of all (in case you don’t know what a bookmarklet is): Bookmarklets are tiny Javascript programs that you store in Bookmarks which when you open the bookmark will run on whatever page you are currently viewing… for example copying a snippet from an article and pasting it into your blog or highlighting images or … well just about anything that a website can do. Pretty much any popular site (Google, Facebook, …) offers bookmarks for various purposes.
The problem is that apparently very few Bookmarklet developers know how to provide icons. Hopefully my little post can change that at least a bit 🙂
It’s really quite simple: Bookmarklets usually have this form:
javascript:alert(“My functionality”);void(0);
Most people put that void(0); there automatically, but it’s important to realize what it actually does: It prevents the code from returning anything. Why do we do that? Because otherwise we’d trigger another behaviour of javascript: urls. Something that I usually like to call “poor man’s data: urls”. You see, anything a javascript url call returns is processed as HTML. So javascript:”<!DOCTYPE html><html><head><title>Hello World</title></head><body>Hello World</body></html>”; actually sends you to a HTML document.
So, let’s recap: A javascript: url can either be a bookmarklet or a document. Well, that’s not quite correct, it’s actually always both, we just use one of these functions at a time. We can actually have both at the same time in various ways, the one that’s most important in our case is that we want the javascript: url to behave like a document when the user clicks in on the webpage, but like a bookmarklet after the user has added it as one. The reason being that documents can have icons. And since the url will be identical, so will the bookmarklet.
So first set up a document javascript: url with an icon:
javascript:'<!DOCTYPE html><html><head><title>Hello World</title><link rel=”icon” type=”image/png” href=”http://www.tapper-ware.net/devel/js/JS.Bookmarklets/icons/next.png” /></head><body>Hello World</body></html>’;
Go ahead, click it 🙂 . You’ll see a nice little play button as icon. Drag the title bar onto the bookmarks toolbar and you’ll see that it retains the icon and as an added bonus the title. Don’t worry about the HTML code bloating up your Bookmarklet, we won’t have to include it directly in the final version, but it’s easier to understand this way.
So, now we need a branch so that it will show the content only when clicked on the original page. Again, there are different ways, for now we’ll just stick with the easiest one of checking for a variable that we are reasonably sure will only exist on the original page:
javascript:window[‘bm.dummy@tapper-ware.net’]=true;void(0);
javascript:if(window[‘bm.dummy@tapper-ware.net’]){ ‘<!DOCTYPE html><html><body>My document</body></html>’; }else{ alert(‘My functionality’); void(0); }
Now, we only need the document content if the variable exists, so we can use it to transport the content instead of including it literally in the bookmarklet, bringing the size of the Bookmarklet down dramatically and freeing us from the requirement to have really compact HTML:
javascript:window[‘bm.dummy@tapper-ware.net’]='<!DOCTYPE html><html><body>My document</body></html>’;void(0);
javascript:var bmi=window[‘bm.dummy@tapper-ware.net’]; if(bmi) bmi; else{ alert(‘My functionality’); void(0); }
You could of course also introduce some randomness into the id if you’re afraid websites will try to block it, I’ll leave that up to you.
At the end of the day, you’re whole bookmarklet could then look something like this:
javascript:
var id=’bm.next.’+((Math.random()*9999)|0)+’@tapper-ware.net’;
window[id]='<!DOCTYPE html><html><head><title>Next</title><link rel=”icon” type=”image/png” href=”http://www.tapper-ware.net/devel/js/JS.Bookmarklets/icons/next.png” /></head><body>This is a bookmarklet. Drag its tab to your bookmarks toolbar to add it. Click the resulting button on any page to automatically find links containing the word next</body></html>’;
document.location=’javascript: if(window[“‘+id+'”]){window[“‘+id+'”]; }else{ (function(){ var f=function(e){ return !!(/next/i).exec(e.textContent)}; var l=document.querySelectorAll(“a”); for(var i=0;i<l.length;i++) if(f(l[i])) document.location=l[i].href; })(); void(0); }’;
void(0);
There are numerous way to automate this or make it prettier, but I’ll leave that to you. So long 🙂