Yesterday I got a question on how to make my Bookmarklet-with-icon code work and sadly, it seems to be broken now. So I set out to find another method and strangely enough the solution that works with modern Firefox versions is quite simple and elegant:
Open the bookmarklet in "page mode" once after the user has added it as bookmarklet. This may sound like something that’s terribly hard to detect, but with a few simple tricks it’s not much of an issue: Mainly because you can make it so that the user barely notices if it fires to often.
- Just like the original bookmarklet-with-icon code, adding icons still relies on the behavior that a javascript: url which returns a string will cause the browser to display that string as a HTML document. So, the first step (again) is saving the HTML string somewhere. Of course, you can still add a bit of randomness, but for simplicity’s sake we’ll leave it out for now:
<script> top["bookmarkletv2sample@tapper-ware.net"] = '' +'<!DOCTYPE html>' +'<html>' +'<head>' +'<title>My Bookmarklet</title>' +'</head>' +'<body></body>' +'</html>' ; </script>
- Now, we add the magic favicon sauce:
<script> top["bookmarkletv2sample@tapper-ware.net"] = '' +'<!DOCTYPE html>' +'<html>' +'<head>' +'<title>My Bookmarklet</title>' +'<link rel="icon" href="http://www.my.domain/favicon.ico" />' +'</head>' +'<body></body>' +'</html>' ; </script>
- Like I said, we want that page to only appear very briefly, so we add a history.back(); call that will take us right back to the previous page. I’ve added a timeout as well, which is probably not necessary, but with hacks like that it’s better to err on the side of caution. It’s also a good idea to split the closing script tag to prevent any browser from misinterpreting it as the end of the current script block:
<script> top["bookmarkletv2sample@tapper-ware.net"] = '' +'<!DOCTYPE html>' +'<html>' +'<head>' +'<title>My Bookmarklet</title>' +'<link rel="icon" href="http://www.my.domain/favicon.ico" />' +'</head>' +'<body>' +'<script>' +'window.onload=function(){' +'window.setTimeout(function(){' +'history.back();' +'},250);' +'};' +'</scr'+'ipt>' +'</body>' +'</html>' ; </script>
- And that’s pretty much it for our magic assign-icon-from-within-bookmarklet page. Now we just have to change the actual bookmarklet to return that HTML string instead of running the bookmarklet code whenever a thusly-named HTML string exists on the current page. Assuming our bookmarlet is a plain old
alert("This is my bookmarklet");void(0);
, we have to wrap it into a little if-block like this:
if(top["bookmarkletv2sample@tapper-ware.net"]){ top["bookmarkletv2sample@tapper-ware.net"]; }else{ alert('This is my bookmarklet'); void(0); }
which, written as a bookmarklet one-liner, turns into
<a href="javascript:if(top['bookmarkletv2sample@tapper-ware.net']){top['bookmarkletv2sample@tapper-ware.net'];}else{alert('This%20is%20my%20bookmarklet');void(0);}">My Bookmarklet</a>
- If you put those blocks somewhere on your page it will already work… sort of: If you drag the link to your bookmarks-toolbar, then click it, you’ll briefly see an empty page and the icon will appear. Now, all we have to automate is that one click. Luckily, all we have to do for that is listen for a dragend event, which occurs whenever the user drags the link anywhere. It also occurs during any other drag operation but since that brief refresh is barely noticeable it doesn’t really matter if we try to assign the icon too often. All we have to do for that is add an ondragend attribute to the a element:
ondragend="this.click();"
Which finally turns our “A” element into this:
<a ondragend="this.click();" href="javascript:if(top['bookmarkletv2sample@tapper-ware.net']){top['bookmarkletv2sample@tapper-ware.net'];}else{alert('This%20is%20my%20bookmarklet');void(0);}">My Bookmarklet</a>
And that’s all there is to it. Include the link and the script element on your page, tell the users that they should add it by dragging the link and that it won’t work on the current page, adjust favicon-url and exchange the example with your own JS code. Done.
Hi,
Your example is working fine on the latest Firefox. However it’s not working on ie8 and the latest Opera, Maxthon and Chrome. (tested on windows 7). Is there a solution?
I added the following code to set the favicon when the user saves it with “right click”->”bookmark this link” (working in FF):
<a oncontextmenu="rgtclick(event,this)"…. (in the url)
function rgtclick(e,t){
$(window).one(“focus”,function(){
t.click();
});
}
…
kb
I’m not at my PC right now, but you could combine it with the technique from the previous article to make it compatible with all Firefox version… but I don’t think that will help chrome, opera or ie/maxthon.
I find the easiest way is to hijack a bookmark. Just bookmark a page that has a favicon that you want to use. You may need to click on the bookmark to have it load the favicon from the site that it links to. Once you have the favicon, then, go to the bookmark, right click, and choose properties. You can then change the “location” to the javascript code for the bookmarklet you want to have associated with the favicon. Tip: To differentiate a bookmarklet from a bookmark, I change the “name” in the properties tab to whatever preceeded by M:, so for example, if the bookmarklet was for creating a shortened URL using goo.gl, I would name that “M:Goo.gl”
Howdy. Simply just planned to ask a quick problem. Now i’m kafgbebgeege
Hello, for the library I work at I’ve created a bookmarklet – javascript:void((function(){location.href=’https://ccl.idm.oclc.org/login?qurl=’+encodeURIComponent(location.href);})()); – and I would like it to show a favicon that’s branded for our university. Right now it just shows a globe. I know how to use a browser extension to change the favicon after it’s been added as a bookmark but I don’t want to ask my library users to have to do that. I’d like the favicon set when the bookmarklet is dragged and dropped onto the bookmark bar. Is that possible? The code listed here looks like it is expecting a webpage. My javascript is not in a webpage but is the bookmark’s path. Thank you for your time.