Better, Stronger, Safer jQuerify Bookmarklet
read 55 commentsA long time ago I built myself a little bookmarklet to load jQuery on pages that don't already have it. The idea was to allow me to play around with any page on the web, using jQuery in the Firebug (and now Safari or IE8) console. I blogged about it, got lots of great feedback, and then blogged about an improved version. Now that a lot more great feedback has come through the comments of the updated bookmarklet post, I've decided to update it one more time.
The Bookmarklet
Update: May 7, 2012
Apparently, Safari 5.1 is stricter than other browsers in its enforcement of URL encoding for bookmarklets. The literal "%" needs to be converted to "%25" — something my bookmarklet generator was not doing when it encountered el.style.left='50%'. I've updated the bookmarklet now, so it should work in Safari 5.1 as well as other browsers. ( cf. http://stackoverflow.com/questions/7324022/safari-5-changes-on-use-of-javascript-bookmarklets )
To use the bookmarklet, drag the following link to your bookmark/favorites list:
» jQuerify «
Then, when you're on a page in which you want to play around with jQuery in the console, just click the bookmarklet.
Problems with the Other One
The biggest problem with the former version was that it didn't work when other libraries that use the $ function, such as Prototype and Mootools, were already loaded on the page. A number of people in the comments suggested that I simply add a jQuery.noConflict(); line to the script. But I wasn't crazy about the idea of having to use jQuery() instead of $() even if no other libraries had been loaded.
Another problem, one that I noticed while testing my new version, was that sometimes the jQuery file that I was inserting from the Google CDN wouldn't fully load by the time I attempted to use it later in the bookmarklet. At least, I think that's what was going on. In any case, it was throwing a "jQuery is not defined" error.
A Few Improvements in This One
To handle the problems, I'm having the script do a few things differently:
- Set up a counter to check 10 times if jQuery is loaded before giving up.
- Use a setTimeout to put a one-quarter-second (250ms) delay interval in between attempts.
- Check if the
$()function is already being used by another library. If it is:- use jQuery's $.noConflict function to release the
$()to the other library. - set
$jqas an alias tojQueryfor convenience. - mention in the flash notice that jQuery is in noConflict mode and that
$jq()should be used instead of$().
- use jQuery's $.noConflict function to release the
- If after multiple attempts jQuery still won't load for some reason, set the flash notice's message accordingly and then remove it through plain old JavaScript rather than jQuery.
Update
Based on a few comments, I've updated the script one more time to "basically watch the onload and readyState, and fire the callback, thus removing the necessity to poll," as Paul Irish describes below.
The script also removes references to script after success now, as suggested below, to avoid a memory leak.
I updated the bookmarklet link above. Here is the updated script:
- (function() {
- var el=document.createElement('div'),
- b=document.getElementsByTagName('body')[0],
- otherlib=false,
- msg='';
- el.style.marginLeft='-110px';
- el.style.top='0';
- el.style.left='50%';
- el.style.padding='5px 10px';
- el.style.zIndex = 1001;
- el.style.fontSize='12px';
- el.style.color='#222';
- el.style.backgroundColor='#f99';
- if(typeof jQuery!='undefined') {
- msg='This page already using jQuery v'+jQuery.fn.jquery;
- return showMsg();
- } else if (typeof $=='function') {
- otherlib=true;
- }
- // more or less stolen form jquery core and adapted by paul irish
- function getScript(url,success){
- var script=document.createElement('script');
- script.src=url;
- var head=document.getElementsByTagName('head')[0],
- // Attach handlers for all browsers
- script.onload=script.onreadystatechange = function(){
- || this.readyState == 'loaded'
- || this.readyState == 'complete') ) {
- success();
- script.onload = script.onreadystatechange = null;
- head.removeChild(script);
- }
- };
- head.appendChild(script);
- }
- getScript('http://code.jquery.com/jquery.min.js',function() {
- if (typeof jQuery=='undefined') {
- msg='Sorry, but jQuery wasn\'t able to load';
- } else {
- msg='This page is now jQuerified with v' + jQuery.fn.jquery;
- if (otherlib) {msg+=' and noConflict(). Use $jq(), not $().';}
- }
- return showMsg();
- });
- function showMsg() {
- el.innerHTML=msg;
- b.appendChild(el);
- window.setTimeout(function() {
- if (typeof jQuery=='undefined') {
- b.removeChild(el);
- } else {
- });
- if (otherlib) {
- $jq=jQuery.noConflict();
- }
- }
- } ,2500);
- }
- })();
Let me know if this one causes any problems.
















My jQuery bookmarklet: http://www.saltarintro.com/wp/2009/03/28/bookmarklets-con-jquery/. (spanish)
Rather than using setTimeout to repeatedly check and see if the script is loaded, you can use the onload event handler for the script itself. When the script loads, the onload event fires for the script element, and you can then notify the user that jQuery has loaded.
Looking good Karl! One suggestion: a small helper function I use quite a lot (when jQuery isn't available) for adding styles to elements:
You're awesome. But then, you already knew that. ;)
Thanks!
Nice stuff! Did you ever checkout the jQuery console?
http://onehackoranother.com/2008/10/jquery-javascript-console-bookmarklet/
I've been using this for a while now.
Glad you like it, Cody - as of a few weeks ago there is a slightly newer version at Github ( http://github.com/jaz303/jquery-console/tree/master ).
(sorry for the hijack, just saw this in my referrer logs :)
Hey Jason,
No problem on the hijack thing. :) I just cloned your console from Github this evening. Great stuff!
@Jason, using the
onloadhandler withSCRIPTelements doesn't work in Internet Explorer or Safari. Here's a cross-browser "lazy-loading" solution: http://ajaxian.com/archives/a-technique-for-lazy-script-loadingWith getting external script from inside a bookmarklet, an emerging standard is to basically watch the onload and readyState, and fire the callback, thus removing the necessity to poll.
Here's some getScript code to consider.
And it's worth noting you're not doing the full
noConflict(true), but I certainly don't mind having both$jqandjQueryavailable.The version number additions are most good; thanks for that. Cheers
I think you can replace the synchronization code by putting most of the script into a seperate file, and loading both jQuery and your script using regular script tags. That way you can rely on the browser to execute both scripts in sequence.
You could also check the version of jQuery that is loaded. Here's how I add jQuery before then loading my own bookmarklet script:
http://www.badlydrawntoy.com/static/960grid/js/960grid-bookmarklet.js
Thanks, everyone, for the excellent suggestions so far!
@sergiomas - looks nice! It doesn't have any of the version messaging, but it's definitely elegant.
@James - that's a great little function. I'm not sure it's worth putting into a bookmarklet if it's only going to be used once, but I really like that sort of thing in general, so thanks!
@Cody - I haven't checked out the jQuery console bookmarklet. But I will now. :)
@Jason, James, Paul Irish, and Jörn Zaefferer - great ideas for avoiding the polling thing. I'll definitely look into all of them.
@Paul Irish - yeah, I figured it wasn't worth doing the extreme noConflict since I'm not loading it if another version already exists. The $jq() is just a convenience, and -- you're right -- either that or jQuery will do.
@Howie, I am checking the version of jQuery.
Just some nitpicks
This is a more reliable way to detect jQuery
if(window.jQuery && jQuery.fn && jQuery.fn.jquery)
And to detect other libraries
if(window.$)
even $ is assigned to a non-function, we should not overwrite to prevent conflict.
Very nice articles on JQuiery loved every bit of it.. thanks for all the help!
Norman Flecha
http://www.straightalk.biz/links/home.php
I just posted my own jQuerify bookmarklet version based on your improved version.
It was just a javascript bookmarklet exercise, but I think it's clean.
http://coder-zone.blogspot.com/2009/05/jquery-bookmarklet.html
Thanks for the great idea and for the code!
Google cannot show this page on top of its results for "jquerify" keyword. You should add a note to the previous posts to point here.
Thanks, Serkan. I added a note.
I'm working on a bookmarklet that popups up a window and grabs some information from the page to submit a form back to my website. I've done this already for the most part with regular old javascript... could I use this code in theory to add jQuery to a page if it doesn't exist and use jQuery for improved UI of the bookmarklet interface? It looks like it, but i wanted to open that question up to the experts. :)
Great bookmarklet! Thanks for explaining in detail, very useful.
It's not working for me. When I drag & drop the bookmarklet into my bookmarks, it doesn't get the full function. If you click on the bookmarklet and copy link location, you can see the failure. It doesn't get the full function, instead it cuts somewhere near head=document.getElementsByTagName("head")[0]
Also the bookmarklet version and the unbookmarkleted version don't seem to be the same. I think there is a problem with the bookmarklet version, because the unbookmarkleted version works perfectly in Firebug command line.
The working bookmarklet for me is;
javascript:(function(){var%20s=document.createElement('script'),el=document.createElement('div'),b=document.getElementsByTagName('body')[0];var%20otherlib=false,startCounter=tryCounter=10,delay=250,msg='';s.setAttribute('src','http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js');el.style.position='fixed';el.style.height='32px';el.style.width='220px';el.style.marginLeft='-110px';el.style.top='0';el.style.left='50%';el.style.padding='5px%2010px%205px%2010px';el.style.fontSize='12px';el.style.color='#222';el.style.backgroundColor='#f99';if(typeof%20jQuery!='undefined'){msg='This%20page%20already%20using%20jQuery%20v'+jQuery.fn.jquery;return%20showMsg();}else{if(typeof%20$=='function'){otherlib=true;}document.getElementsByTagName('head')[0].appendChild(s);}function%20showMsg()%20{el.innerHTML=msg;b.appendChild(el);window.setTimeout(function()%20{if(typeof%20jQuery=='undefined'){b.removeChild(el);}else{jQuery(el).fadeOut('slow',function(){jQuery(this).remove();});if(otherlib){$jq=jQuery.noConflict();}}},2500);}var%20tryjQuery=function(){setTimeout(function(){if(typeof%20jQuery=='undefined'){if(tryCounter){tryCounter--;tryjQuery();}else{msg='Sorry,%20but%20after%20'+startCounter+'%20attempts,%20jQuery%20hasn\'t%20loaded';showMsg();}}else{msg='This%20page%20is%20now%20jQuerified%20with%20v'%20+%20jQuery.fn.jquery;if(otherlib){msg+='%20and%20noConflict().%20Use%20$jq(),%20not%20$().';}showMsg();}},delay);};tryjQuery();})();
So sorry about that. I think WordPress did something funky to the bookmarklet when I updated and re-saved the post last night. I'll fix it as soon as I can.
Sorry again for the problems. It should be good to go now.
Perfect, thx !
Your tutorials and ideas are simply great. Something like you cannot find anywhere else.
Great bookmarklet!
Thanks Karl, I was thinking of making a scriptlet like this for quite a while so that i can play with DOM elements live on site who don't have jQuery. Looks like you've done it right.
This is a very useful bookmarklet. Thank you, Karl.
One minor aesthetics issue I found is that with IE7 and IE8 in quirks mode, the message "This page is now jQuerified" is displayed below the bottom left of the page. This is due to IE not supporting position=fixed in that mode.
To workaround this, I added the following lines after the block of
el.styleassignments:Not sure if this is the best way to detect quirks mode, but other people might be able to come up with something better.
God I love you.
What do you use to convert your JS code from "unbookmarkleted" to "bookmarkleted" form? Thanks.
Hi Kenneth,
I use the JavaScript Tools TextMate bundle, which can be found on GitHub. You can also try the web-based bookmarklet crunchinator.
Thanks for that, I'm using the TextMate bundle now as well.
Just FYI... The code in the the Plain Text version of your lastest code doesn't match the filtered version there is a || missing around line 31 and also the use of double quotes around the head tag causes issues as well which isn't in you previous version.
Fixing those it seems to work like a dream, thanks, Ken.
Thanks for mentioning those problems, Kenneth. Finicky syntax-highlighting plugin. I've updated the code sample, so hopefully the plain text version will match the filtered version now.
Thanks for the bookmarklet - it's getting quite lengthy, but more full featured. Thanks again for sharing.
Just an fyi the code on line 53 is not escaped properly. Simple oversight, but easily found with a good code coloring scheme.
53. ... jQuery hasn't loaded
Should be...
53. ... jQuery hasn\'t loaded
Good catch! It's fixed now. Actually, though, that error was in the older version of the script. Take a look at the update, which is even more robust, a little farther down in the entry.
You may wish to update your getScript function to include IE memory leak prevention:
Post this right after the callback success() line and you're good.
Thanks so much for the suggestion. I've updated the bookmarklet.
I really really love this idea, but I would find it more convenient if it'd "pop up" (div with text area and such) a little text area to let me enter my jQuery and a button to execute it against the page. I have a webpart that does this for SharePoint pages and it's super convenient. Sure, I can open a console, but if I just want to play with something quick, I'd like the pop up.
A great example is SelectorGadget.
you don't need four values to specify - two values are sufficient. the first is for the top and bottom and the second for the left and right.
padding: '5px 10px'
is the shorter version of
padding: '5px 10px 5px 10px'
Thanks, E.
Updated.
I've created a miniframework to build bookmarklets easily and quickly, loading css and javascript files (even jquery). You can check it here: http://idc.anavallasuiza.com/bookmarklets/
just did a little thing that helps you save paper when printing a page with no printable version.
it was possible to done thanks to your work :)
tell me what you think
http://bit.ly/9RuSGs
Just FYI, the way your code is currently setup, you can't use your convenience alias $jq (if another lib is detected) within your custom code, unless your custom code is run after the showMsg() function has been called, because you've defined $jq() within that showMsg() function.
For example, say I create myFunction() to contain all my $jq() reliant code, then I call it from within the
elsesection of your jQuery check, like so:If myFunction then starts making $jq calls, they all fail, stating "$jq is not defined". However, they work fine if I just change those $jq() calls to jQuery() calls. Haven't tested this with $() calls, though. So in the above example, myFunction() ends up being called before the $jq() convenience alias is defined by your script.
Again, I noticed that the $jq() alias is actually being defined from within your showMsg() function. However, since it's completely unrelated to the functionality required for showing a message, perhaps you can simply move it to the
if (otherlib)conditional that already exists within thatelsehalf of the conditional that checks if jQuery is undefined. After all, it's clearly unrelated to showing a message, so there's no need to have anotherif (otherlib)conditional.Also, perhaps you could overhaul your code just a bit further to better demonstrate just how to best insert one's own jQuery-reliant code, whether it be via the myFunction() concept I'm using, or via some other more optimal approach as you see fit. I just think that would make it easier for those who see this, but don't necessarily pick up on the fact that they can place their jQuery-reliant code in that
elsehalf of the jQuery-undefined conditional.Granted, you could also just replace the showMsg() function with your own entirely, but then you'd lose the $jq() alias if you didn't move it yourself, since that's where you've currently defined it. So moving the $jq() alias definition to the jQuery check conditional is plenty appropriate.
Just my 2¢ :)
Cheers!
Great bookmarklet! I always use this with Firebug to debug my webpages.
In Google Chrome, it gives error
Uncaught SyntaxError: Unexpected number
in the js console.
FYI, in the latest Chrome release, trying to drag the link to the bookmarklet at the top of the page into the bookmark bar will cause the browser to crash.
Reason: there's an escaped space at the beginning of the script
javascript:%20(function()...Workaround: instead of dragging the bookmarklet, bookmark this page, then edit the bookmark and replace the page url with the bookmarklet script (but remove the errant %20 before saving).
Thanks for the report, Michelle! I just updated the href for the bookmarklet, so it should work now.
It's not working on Safari 5.1.5
Even when replacing % with %25
I get in the console : SyntaxError: Expected an identifier but found 'jQuery' instead
I just updated the bookmarklet, and it's working for me in Safari 5.1.5 now. Can you grab the latest, above, and let me know how that goes?
Can we have it link to the developer version, not the minified version? I want to see the full names of the parameters for functions ,comments, etc
Hi Ali,
You can see the "developer version" in the entry itself.
If you load this on an HTTPS page you get the warning (at least in Chrome) "Page has insecure content - do you want to load?" which is because the jquery link you are using is with HTTP. You can't just fix that by switching it to HTTPS for SSL because jQuery does not sign their SSL cert with a certified certificate. However you can use this link instead:
https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js
That link will load the latest version of the v1 family of jQuery, so right now v 1.7.
Also note you can use this link to load the latest version of the 1.7 family:
https://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js
Or this link to load the latest version of the 1.7.1:
https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js
Also works for older versions. And if your script was really tricky you could check the protocol that the current page is using and switch between using HTTPS and HTTP instead of just defaulting to HTTPS, but even HTTPS would be better than just HTTP as it would work without error for both types of pages.
Thanks for a great post, I've been using this one (and before that the original one) for quite a long time.
Good catch on the https issue. To avoid the problem, you can use the Google CDN URL without the protocol:
//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.jsgreat job.
Unfortunately, it does not work while browsing facebook with google chrome. Same issue with google result pages (not cached pages)
It works fine in IE (9+) in compatibility mode.
A few french web site (20minutes.fr) have random troubles (not displaying jquery version before 2 or 3 click attempts). Have to wait the whole page loaded before clicking on the bookmarklet.
For the google search results pages, you might have better luck if you change the URL for jQuery. I have it set to http://code.jquery.com/... but if the search results are on the https protocol, you should probably use the Google CDN. Change the URL to //ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js
For Facebook, it looks like they only allow scripts to load from a small set of trusted domains.
When I tried to load the script, I got this error output in the console:
Sorry, but there is nothing I can do about that.
Got the book mark but in console, I don't see the dollar prompt. How can I get it?